package com.hjw.httpclient.https;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.junit.Test;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * @author hjwStrart
 * @time 2022-11-21 21:10
 * @version: 1.0
 */
public class Demo {

    /**
     * 测试使用 HttpClient 访问不安全的Https网站，配置HttpClient绕过https安全认证
     * 否则会报错：javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
     * PKIX path validation failed: java.security.cert.CertPathValidatorException:
     * timestamp check failed
     * @throws Exception
     */

    @Test
    public void method() throws Exception {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", trustHttpsCertificates())
                .build();
        // 创建一个 ConnectionManager 对象
        PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager(registry);
        // 定制 CloseableHttpClient对象
        HttpClientBuilder httpClientBuilder = HttpClients.custom().setConnectionManager(pool);
        // 配置好HttpClientBuilder之后，通过builder方法获取HttpClient对象
        CloseableHttpClient httpClient = httpClientBuilder.build();
//        CloseableHttpClient httpClient = HttpClients.createDefault(); //
        String urlStr = "https://www.diaoyur.com/h/";
        // 创建一个 HttpXXX 对象，XXX是请求方式
        // 构造 HttpGet 请求对象
        HttpGet httpGet = new HttpGet(urlStr);
        // 通过HttpGet对象可以设置请求头信息，防止服务器检测出我们的请求不是真实请求
        // 可以在请求头中添加User-Agent属性，解决HttpClient被认为不是真人行为的方法
        httpGet.addHeader("User-Agent", "");
        // 设置防盗链，避免网站的图片资源被盗取,value是要保护的网址的url
        httpGet.addHeader("Reference", "https://www.baidu.com");
        // 构造一个可关闭的响应对象
        CloseableHttpResponse response = null;
        try {
            // httpClient 执行 Get 请求，获取到响应对象
            response = httpClient.execute(httpGet);
            // 获取响应状态码
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200)
                System.out.println("响应正常");
            else
                System.out.println("响应异常");
            // 从响应对象中获取到响应结果
            /*
            HttpEntity不仅可以做为响应结果的承载体，也可以做为请求的参数实体，有很多的实现
             */
            HttpEntity entity = response.getEntity();
            // 工具类 EntityUtils，用来操作 HttpEntity 的
            String responseStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            System.out.println("通过EntityUtils工具类读取到的响应内容：" + responseStr);
            // 确保流关闭，实体被消费
            EntityUtils.consume(entity);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 创建支持安全协议的连接
     *
     * @return
     * @throws Exception
     */
    private ConnectionSocketFactory trustHttpsCertificates() throws Exception {
        SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustStrategy() {
            // 判断是否信任url
            @Override
            public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                return true;
            }
        });
        SSLContext sslContext = builder.build();
        return new
                SSLConnectionSocketFactory(sslContext,
                new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}
                , null, NoopHostnameVerifier.INSTANCE);
    }
}
